package exec

import (
	"hundsun.com/hsl/hschain/common/log"
	"hundsun.com/hsl/hschain/common/types"
	managecomm "hundsun.com/hsl/hschain/contract/native/manage/common"
	execcomm "hundsun.com/hsl/hschain/executor/common"
	"hundsun.com/hsl/hschain/protos/common"
	"hundsun.com/hsl/hschain/protos/execute"
	protosledger "hundsun.com/hsl/hschain/protos/ledger"
	protosmanage "hundsun.com/hsl/hschain/protos/manage"
)

func init() {
	RegisterExecution(managecomm.CommitExecName, NewCommitExecution)
}

// CommitExecution 提交提案节点实例
type CommitExecution struct {
	ExecutionAdaptor
}

// NewCommitExecution 新建提交提案执行节点
func NewCommitExecution(id, step uint32, proposal *protosmanage.ManageFlowProposal, properties *protosmanage.ExecProperties) Execution {
	var exec = &CommitExecution{}
	exec.InitAdaptor(id, step, proposal, properties)
	return exec
}

// Run 运行
func (e *CommitExecution) Run(ctx *execcomm.ExecContent, gtx *execute.GroupedTransaction) error {
	if e.GetProposal() != nil {
		switch e.GetProposal().GetType() {
		case protosmanage.ProposalType_UserGroupProposalType:
			proposal := e.GetProposal().GetUserGroup().GetProposal()
			groupType := e.GetProposal().GetUserGroup().GetGroupType()
			var validatorInfo = &protosmanage.ManageFlowValidatorInfo{
				Validators: proposal,
			}
			kv, err := managecomm.UserGroupKV(groupType, validatorInfo)
			if err != nil {
				log.Errorf("generate group info kv failed, err: %s", err.Error())
				gtx.TxExecRst.Receipt.TxStatus = protosledger.TransactionReceipt_FAILED_OTHER_REASON
				return err
			}
			ctx.GetStateHandle().SetLocal(kv.Key, kv.Value)
			gtx.TxExecRst.Kvs = append(gtx.TxExecRst.Kvs, kv)
			gtx.TxExecRst.Receipt.Logs = append(gtx.TxExecRst.Receipt.Logs,
				&protosledger.Log{Ty: managecomm.TyLogUserGroupUpdate, Data: kv.Value})

			commitProposalRWStatus := &execute.RWStatus{Key: kv.Key, RwStatus: 1}
			gtx.VarsRWStatus = append(gtx.VarsRWStatus, commitProposalRWStatus)

			log.Infof("commit manage proposal info of flow %d successfully, proposal: %v", e.GetFlowID(), validatorInfo.Validators)
			return nil
		case protosmanage.ProposalType_SysParamProposalType:
			stepParam := e.GetProposal().GetSysParam().GetStepSysParam()
			sysParamKV, err := managecomm.SysParamKV(stepParam)
			if err != nil {
				log.Errorf("generate consensus param kv failed, err: %s", err.Error())
				return err
			}
			ctx.GetStateHandle().SetLocal(sysParamKV.Key, sysParamKV.Value)
			gtx.TxExecRst.Kvs = append(gtx.TxExecRst.Kvs, sysParamKV)
			gtx.TxExecRst.Receipt.Logs = append(gtx.TxExecRst.Receipt.Logs,
				&protosledger.Log{Ty: managecomm.TyLogSysParamUpdate, Data: sysParamKV.Value})
			gtx.TxExecRst.Receipt.Events = append(gtx.TxExecRst.Receipt.Events,
				&common.ContractEvent{
					TransactionHash: gtx.GetTx().Hash(),
					BlockNumber:     ctx.GetHeight(),
					Name:            string(types.GeneSysParamUpdateKeyPrefix()),
					Data:            sysParamKV.Value,
				})

			mainValidatorRWStatus := &execute.RWStatus{Key: sysParamKV.Key, RwStatus: 1}
			gtx.VarsRWStatus = append(gtx.VarsRWStatus, mainValidatorRWStatus)

			log.Infof("commit consensus update proposal info of flow %d successfully, proposal: %v", e.GetFlowID(), stepParam)
			return nil
		case protosmanage.ProposalType_ConsensusUpdateProposalType:
			consensusProposal := e.GetProposal().GetConsensusUpdate().GetStepConParam()
			consensusParamKV, err := managecomm.ConsensusParamKV(consensusProposal)
			if err != nil {
				log.Errorf("generate consensus param kv failed, err: %s", err.Error())
				return err
			}
			ctx.GetStateHandle().SetLocal(consensusParamKV.Key, consensusParamKV.Value)
			gtx.TxExecRst.Kvs = append(gtx.TxExecRst.Kvs, consensusParamKV)
			gtx.TxExecRst.Receipt.Logs = append(gtx.TxExecRst.Receipt.Logs,
				&protosledger.Log{Ty: managecomm.TyLogConsensusUpdate, Data: consensusParamKV.Value})
			gtx.TxExecRst.Receipt.Events = append(gtx.TxExecRst.Receipt.Events,
				&common.ContractEvent{
					TransactionHash: gtx.GetTx().Hash(),
					BlockNumber:     ctx.GetHeight(),
					Name:            string(types.GeneConsensusUpdateKeyPrefix()),
					Data:            consensusParamKV.Value,
				})

			proposalRWStatus := &execute.RWStatus{Key: consensusParamKV.Key, RwStatus: 1}
			gtx.VarsRWStatus = append(gtx.VarsRWStatus, proposalRWStatus)

			log.Infof("commit consensus update proposal info of flow %d successfully, proposal: %v", e.GetFlowID(), consensusProposal)
			return nil
		default:
			log.Error("unknown proposal type")
			return managecomm.ErrUnknownManageFlowProposal
		}
	}
	log.Infof("proposal is nil, no need to commit. current flow id: %d", e.GetFlowID())
	return nil
}
